package nl.moviefan.site.vestigingen;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import nl.moviefan.site.model.ArtikelFilm;
import nl.moviefan.site.model.Datadrager;
import nl.moviefan.site.model.Genre;
import nl.moviefan.site.model.Uitvoering;

/**
 * Deze klasse maakt het mogelijk om te communiceren met de database van een vestiging.
 * 
 * @author Maurice & Eric
 */
public class VestigingConnector {

    private Properties props = new Properties();
    private String drivers = null;
    private String url = null;
    private String username = null;
    private String password = null;
    private Connection cxn;

    /**
     * Constructor, properties worden ingelezen uit het opgegeven properties
     * bestand.
     */
    public VestigingConnector() {
        loadProperties();
    }

    /**
     * Haalt de configuratie gegevens tbv de database verbinding uit het
     * ingelezen properties bestand.
     */
    private void loadProperties() {
        this.drivers = "org.apache.derby.jdbc.ClientDriver";
        this.url = "jdbc:derby://localhost:1527/moviefan";
        this.username = "eric";
        this.password = "123";
    }

    /**
     * Creert de database verbinding. Als er geen bestaande verbinding is wordt
     * deze gemaakt.
     *
     * @return De actieve database verbinding (connection object) of null.
     * @throws SQLException als er een Exceptie plaats vind.
     */
    private Connection getConnection() throws SQLException {
        if (this.cxn == null) {
            try {
                //Connection con;
                Class.forName(this.drivers);
                this.cxn = DriverManager.getConnection(this.url, this.username, this.password);
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(VestigingConnector.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return this.cxn;
    }

    /**
     * Deze method zorgt ervoor dat bij het artikelnummer een artikelID wordt gezocht
     * @param artikelnummer
     * @param con
     * @return het artikelID behorende bij het artikelnummer
     */
    public int findArtikelID(int artikelnummer, Connection con) {
        Connection wCon = null;
        int dbArtikelID = -1;
        try {
            if (con == null) {
                wCon = this.getConnection();
            } else {
                wCon = con;
            }

            wCon = this.getConnection();
            PreparedStatement statement = null;
            statement = wCon.prepareStatement("SELECT * FROM ARTIKEL WHERE ARTIKELNUMMER = " + artikelnummer);

            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                dbArtikelID = rs.getInt("artikelnummer");
            }

        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (con != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return dbArtikelID;
    }

    /**
     * Deze method zorgt ervoor dat bij een klantnummer een klantID wordt gezocht
     * @param klantnummer
     * @param con
     * @return klantID behorende bij het klantnummer
     */
    public int findKlantID(int klantnummer, Connection con) {
        Connection wCon = null;
        int dbKlantID = -1;
        try {
            if (con == null) {
                wCon = this.getConnection();
            } else {
                wCon = con;
            }

            wCon = this.getConnection();
            PreparedStatement statement = null;
            statement = wCon.prepareStatement("SELECT * FROM KLANT WHERE KLANTNUMMER = " + klantnummer);

            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                dbKlantID = rs.getInt("klantid");
            }

        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (con != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return dbKlantID;
    }

    /**
     * 
     * @param artikelnummer
     * @param klantnummer
     * @param date
     * @return 
     */
    public boolean makeReservering(int artikelnummer, int klantnummer, Timestamp date) {
        boolean result = false;
        int numRows = -1;
        Connection wCon = null;
        try {
            wCon = this.getConnection();
            int artikelid = this.findArtikelID(artikelnummer, null);
            int klantid = this.findKlantID(klantnummer, null);

            PreparedStatement statement = null;
            statement = wCon.prepareStatement("INSERT INTO RESERVERING ("
                    + "artikelid, "
                    + "klantid, "
                    + "gereserveerdop) VALUES (?, ?, ?)");
            statement.setInt(1, artikelid);
            statement.setInt(2, klantid);
            statement.setTimestamp(3, date);
            numRows = statement.executeUpdate();
            if (numRows > 0) {
                result = true;
            }

        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (wCon != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return result;
    }

    /**
     * 
     * @param artikelnr
     * @return 
     */
    public boolean getVerhuurStatus(int artikelnr) {
        boolean result = false;
        int numRows = -1;
        Connection wCon = null;
        try {
            wCon = this.getConnection();
            int artikelID = this.getArtikelID(artikelnr);

            wCon = this.getConnection();
            PreparedStatement statement = null;
            statement = wCon.prepareStatement("SELECT * FROM VERHUURREGEL WHERE ARTIKELID = " + artikelID);
            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                result = true;
            }
        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (wCon != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return result;
    }

    /**
     * 
     * @param artikelnummer
     * @return 
     */
    public int getArtikelID(int artikelnummer) {
        Connection wCon = null;
        int artikelID = -1;
        try {
            wCon = this.getConnection();
            PreparedStatement statement = null;
            statement = wCon.prepareStatement("SELECT ARTIKELID FROM ARTIKEL WHERE ARTIKELNUMMER = " + artikelnummer);

            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                artikelID = rs.getInt("ARTIKELID");
            }

        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (wCon != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return artikelID;
    }

    /**
     * 
     * @return 
     */
    public ArrayList<ArtikelFilm> getBeschikbareArtikelen() {
        Connection wCon = null;
        ArrayList<ArtikelFilm> beschikbareArtikelen = new ArrayList();

        try {
            wCon = this.getConnection();
            PreparedStatement statement = null;
            statement = wCon.prepareStatement("SELECT * FROM ARTIKEL WHERE ARTIKELID NOT IN (SELECT ARTIKELID FROM RESERVERING) AND ARTIKELID NOT IN (SELECT ARTIKELID FROM VERHUURREGEL) AND NOT AFGESCHREVEN");
            ResultSet rs = statement.executeQuery();

            ArtikelFilm af = null;
            while (rs.next()) {
                int dbVestigingID = rs.getInt("vestigingID");
                int dbArtikelnummer = rs.getInt("artikelnummer");
                String dbTitel = rs.getString("titel");
                boolean dbAfgeschreven = rs.getBoolean("afgeschreven");
                double dbPrijs = rs.getDouble("prijs");
                boolean dbStatus = rs.getBoolean("status");

                Datadrager dbDatadrager = null;
                dbDatadrager = Datadrager.valueOf(rs.getString("DATADRAGER"));

                Genre dbGenre = null;
                dbGenre = Genre.valueOf(rs.getString("GENRE"));

                Uitvoering dbUitvoering = null;
                dbUitvoering = Uitvoering.valueOf(rs.getString("UITVOERING"));

                int dbDuur = rs.getInt("duur");
                String dbProducent = rs.getString("producent");
                String dbProductiemaatschappij = rs.getString("productiemaatschappij");
                String dbFilmcast = rs.getString("filmcast");
                String dbSamenvatting = rs.getString("SAMENVATTING");

                af = new ArtikelFilm(dbVestigingID, dbArtikelnummer,
                        dbTitel, dbAfgeschreven, dbPrijs,
                        dbStatus, dbDatadrager, dbGenre, dbUitvoering,
                        dbDuur, dbProducent, dbProductiemaatschappij, dbFilmcast, dbSamenvatting);
                beschikbareArtikelen.add(af);
            }
        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (wCon != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return beschikbareArtikelen;
    }

    /**
     * 
     * @param artikelnummer
     * @return 
     */
    public ArtikelFilm getGereserveerdArtikel(int artikelnummer) {
        Connection wCon = null;
        ArtikelFilm af = new ArtikelFilm();

        try {
            wCon = this.getConnection();
            PreparedStatement statement = null;
            statement = wCon.prepareStatement("SELECT * FROM ARTIKEL WHERE ARTIKELNUMMER = " + artikelnummer);
            ResultSet rs = statement.executeQuery();

            while (rs.next()) {
                int dbVestigingID = rs.getInt("vestigingID");
                int dbArtikelnummer = rs.getInt("artikelnummer");
                String dbTitel = rs.getString("titel");
                boolean dbAfgeschreven = rs.getBoolean("afgeschreven");
                double dbPrijs = rs.getDouble("prijs");
                boolean dbStatus = rs.getBoolean("status");

                Datadrager dbDatadrager = null;
                dbDatadrager = Datadrager.valueOf(rs.getString("DATADRAGER"));

                Genre dbGenre = null;
                dbGenre = Genre.valueOf(rs.getString("GENRE"));

                Uitvoering dbUitvoering = null;
                dbUitvoering = Uitvoering.valueOf(rs.getString("UITVOERING"));

                int dbDuur = rs.getInt("duur");
                String dbProducent = rs.getString("producent");
                String dbProductiemaatschappij = rs.getString("productiemaatschappij");
                String dbFilmcast = rs.getString("filmcast");
                String dbSamenvatting = rs.getString("SAMENVATTING");

                af = new ArtikelFilm(dbVestigingID, dbArtikelnummer,
                        dbTitel, dbAfgeschreven, dbPrijs,
                        dbStatus, dbDatadrager, dbGenre, dbUitvoering,
                        dbDuur, dbProducent, dbProductiemaatschappij, dbFilmcast, dbSamenvatting);
            }
        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (wCon != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return af;
    }

    /**
     * 
     * @param klantnummer
     * @return 
     */
    public ArrayList<ArtikelFilm> getGereserveerdeArtikelen(int klantnummer) {
        Connection wCon = null;
        ArrayList<ArtikelFilm> gereserveerdeArtikelen = new ArrayList();

        try {
            wCon = this.getConnection();
            PreparedStatement statement = null;
            int klantid = this.findKlantID(klantnummer, null);
            statement = wCon.prepareStatement("SELECT * FROM ARTIKEL WHERE ARTIKELID IN (SELECT ARTIKELID FROM RESERVERING WHERE KLANTID = " + klantid + ")");
            ResultSet rs = statement.executeQuery();

            ArtikelFilm af = null;
            while (rs.next()) {
                int dbVestigingID = rs.getInt("vestigingID");
                int dbArtikelnummer = rs.getInt("artikelnummer");
                String dbTitel = rs.getString("titel");
                boolean dbAfgeschreven = rs.getBoolean("afgeschreven");
                double dbPrijs = rs.getDouble("prijs");
                boolean dbStatus = rs.getBoolean("status");

                Datadrager dbDatadrager = null;
                dbDatadrager = Datadrager.valueOf(rs.getString("DATADRAGER"));

                Genre dbGenre = null;
                dbGenre = Genre.valueOf(rs.getString("GENRE"));

                Uitvoering dbUitvoering = null;
                dbUitvoering = Uitvoering.valueOf(rs.getString("UITVOERING"));

                int dbDuur = rs.getInt("duur");
                String dbProducent = rs.getString("producent");
                String dbProductiemaatschappij = rs.getString("productiemaatschappij");
                String dbFilmcast = rs.getString("filmcast");
                String dbSamenvatting = rs.getString("SAMENVATTING");

                af = new ArtikelFilm(dbVestigingID, dbArtikelnummer,
                        dbTitel, dbAfgeschreven, dbPrijs,
                        dbStatus, dbDatadrager, dbGenre, dbUitvoering,
                        dbDuur, dbProducent, dbProductiemaatschappij, dbFilmcast, dbSamenvatting);
                gereserveerdeArtikelen.add(af);
            }
        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (wCon != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return gereserveerdeArtikelen;
    }

    /**
     * Deze methode zorgt voor het aanmaken van een klant op de lokale database van de vestiging
     * @param vestigingID
     * @param klantnummer
     * @param naam
     * @param achternaam
     * @param straat
     * @param huisnummer
     * @param telefoonnummer
     * @param woonplaats
     * @param username
     * @param wachtwoord
     * @param con
     * @return 
     */
    public boolean insertCustomer(int vestigingID, int klantnummer, String naam, String achternaam, String straat, String huisnummer, String telefoonnummer, String woonplaats, String username, String wachtwoord, Connection con) {
        boolean result = false;
        int numRows = -1;
        Connection wCon = null;
        int credentialID = -1;
        credentialID = this.insertCredential(username, wachtwoord,null);
        if (credentialID != -1) {
            try {
                if (con == null) {
                    wCon = this.getConnection();
                } else {
                    wCon = con;
                }

                wCon = this.getConnection();
                PreparedStatement statement = null;
                statement = wCon.prepareStatement("INSERT INTO klant ("
                        + "vestigingID, "
                        + "credentialID, "
                        + "klantnummer, "
                        + "naam, "
                        + "achternaam, "
                        + "straat, "
                        + "huisnummer, "
                        + "woonplaats, "
                        + "telefoonnummer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
                        new String[]{"ID_COLUMN"});
                statement.setInt(1, vestigingID);
                statement.setInt(2, credentialID);
                statement.setInt(3, klantnummer);
                statement.setString(4, naam);
                statement.setString(5, achternaam);
                statement.setString(6, straat);
                statement.setString(7, huisnummer);
                statement.setString(8, woonplaats);
                statement.setString(9, telefoonnummer);
                numRows = statement.executeUpdate();

                if (numRows >= 1) {
                    result = true;
                }
            } catch (SQLException sqle) {
                Logger.getLogger(VestigingConnector.class
                        .getName()).log(Level.SEVERE, null, sqle);
            } finally {
                if (con != null) {
                    try {
                        wCon.close();
                    } catch (SQLException ex) {
                        Logger.getLogger(VestigingConnector.class
                                .getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
        return result;
    }

    /**
     * 
     * @param username
     * @param wachtwoord
     * @param con
     * @return 
     */
    private int insertCredential(String username, String wachtwoord, Connection con) {
        Connection wCon = null;
        int generatedIndex = -1;
        try {
            if (con == null) {
                wCon = this.getConnection();
            } else {
                wCon = con;
            }

            wCon = this.getConnection();
            PreparedStatement statement = null;
            statement = wCon.prepareStatement("INSERT INTO credential ("
                    + "username, "
                    + "wachtwoord) VALUES (?, ?)",
                    new String[]{"ID_COLUMN"});
            statement.setString(1, username);
            statement.setString(2, wachtwoord);
            statement.executeUpdate();

            ResultSet rs = statement.getGeneratedKeys();
            if (rs.next()) {
                generatedIndex = rs.getInt(1);
            }
        } catch (SQLException sqle) {
            Logger.getLogger(VestigingConnector.class
                    .getName()).log(Level.SEVERE, null, sqle);
        } finally {
            if (con != null) {
                try {
                    wCon.close();
                } catch (SQLException ex) {
                    Logger.getLogger(VestigingConnector.class
                            .getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return generatedIndex;
    }

}
